/*
ID: khymill1
PROG: maze1
LANG: C++
*/
#include <string.h>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <set>
#include <limits.h>

using namespace std;

typedef struct maze {
    bool wall[4];
} maze_t;

struct Node_t {
	int x, y, depth;
	Node_t(int x, int y, int d) :x(x), y(y), depth(d){}
};

int minDis = 0;

typedef pair<int, int> PII;

void bfs(int x, int y, int w, int h, vector<vector<int> > &shortest,  vector<vector<maze> >&adj)
{
	vector<vector<bool> >visited(h, vector<bool>(w, false));
	queue<Node_t > Q;
	Q.push(Node_t(x, y, 1));
	int depth = 1;
	shortest[x][y] = 1;


	while(!Q.empty()) {
		Node_t nod = Q.front();
		int dis = nod.depth;
		//minDis = max(minDis, dis);
		visited[nod.x][nod.y] = true;
		Q.pop();
		if (nod.y > 0 && adj[nod.x][nod.y-1].wall[1] == true && visited[nod.x][nod.y-1] == false) {
			shortest[nod.x][nod.y-1] = dis+1;
			//visited[nod.x][nod.y-1] = true;
			Q.push(Node_t(nod.x, nod.y-1, dis+1));
		}

		if (nod.x > 0 && adj[nod.x-1][nod.y].wall[2] == true && visited[nod.x-1][nod.y] == false) {
			Q.push(Node_t(nod.x-1, nod.y, dis+1));
			//visited[nod.x-1][nod.y] = true;
			shortest[nod.x-1][nod.y] = dis+1;
		}

		if (nod.y <w-1 && adj[nod.x][nod.y+1].wall[3] == true && visited[nod.x][nod.y+1] == false) {
			Q.push(Node_t(nod.x, nod.y+1, dis+1));
			//visited[nod.x][nod.y+1] = true;
			shortest[nod.x][nod.y+1] = dis+1;
		}

		if (nod.x <h-1 && adj[nod.x+1][nod.y].wall[0] == true && visited[nod.x+1][nod.y] == false) {
			Q.push(Node_t(nod.x+1, nod.y, dis+1));
			//visited[nod.x+1][nod.y] = true;
			shortest[nod.x+1][nod.y] = dis+1;
		}
	}
	return;
}

int main()
{
    ifstream fin("maze1.in");
    ofstream fout("maze1.out");
    int w, h;
    fin >> w >> h;
    char input;
    int exitX[2], exitY[2];
    int count = 0;
    if (w == 1 && h == 1) {
        fout << "1" << endl;
        return 0;
    }

    vector<vector<maze> > adj(h, vector<maze>(w));
	 vector<vector<int> > shortest1(h, vector<int>(w));
	  vector<vector<int> > shortest2(h, vector<int>(w));
	input = fin.get();
    for (int i = 0; i < 2*h+1; i++) {
		int test = 0;
        for (int j = 0; j < 2*w+1; j++) {

			do {
				input = fin.get();
			} while(input == '\n');

            if (input == '+')
				continue;
            if (input == ' ') {
                if (i == 0 || i == 2*h) {
                    exitX[count] = i == 0 ? 0 : i/2-1;
                    exitY[count] = j/2;
                    count++;
                    continue;
                }
                if (j == 0 || j == 2*w) {
                    exitX[count] = i/2;
                    exitY[count] = j == 0 ? j : j/2-1;
                    count++;
                    continue;
                }
				if (j%2 == 1 && i%2 == 1)
					continue;
                if (i%2 == 1) {
                    adj[i/2][j/2-1].wall[1] = true;
                   if (j/2 < w) adj[i/2][j/2].wall[3] = true;
                } else if (i%2 == 0) {
                    adj[i/2-1][j/2].wall[2] = true;
                   if (i/2 < h) adj[i/2][j/2].wall[0] = true;
                }
            }
        }
    }
		bfs(exitX[0], exitY[0], w, h, shortest1, adj);
		bfs(exitX[1], exitY[1], w, h, shortest2, adj);
		for (int i = 0; i < shortest1.size(); i++) {
			for (int j = 0;j < shortest1[0].size(); j++) {
				shortest1[i][j] = min(shortest1[i][j], shortest2[i][j]);
				minDis = max(shortest1[i][j], minDis);
			}
		}
		fout << minDis << endl;
    return 0;
}
